// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © BrookstarNZ

//@version=5
indicator("CRYPTO SLAYA TRENDY S/D & S/R", overlay=true)
 
// Get user input
// Trend
autoTL          = input.bool(true, "TREND ON/OFF", group = "TREND")
upperTL1        = input.color(color.new(#E91E63, 5), "TOP COLOR", group="TREND")
middleTL2       = input.color(color.new(#ffffff, 5), "MIDDLE COLOR", group="TREND")
lowerTL3        = input.color(color.new(#00DBFF, 5), "BOTTOM COLOR", group="TREND")
styleOption     = input.string(title="LINE STYLE",options=["Solid ─", "Dotted ┈", "Dashed ╌", "Arrow Left ←", "Arrow Right →", "Arrows Both ↔"], defval="Solid ─", group = "TREND")
lineWidth1      = input.int(2, title="LINE WIDTH", minval=1, maxval = 4, group = "TREND")
expandTrend     = input(false, "EXTEND TREND LINES", group = "TREND")
// Supply & Demand
enableSD        = input(true, "SUPPLY & DEMAND ON/OFF", group="SUPPLY & DEMAND")
mitigation      = input.string('Wick', 'MIGRATION', options = ['Wick', 'Close'], group = "SUPPLY & DEMAND")
length          = input.int(10, 'S/D STRENGTH', minval = 1, group = "SUPPLY & DEMAND")
bear_ext_last   = input.int(1, 'SUPPLY', minval = 1, group = "SUPPLY & DEMAND", inline = 'bear')
bg_bear_css     = input.color(color.new(#ff0015, 90), '', group = "SUPPLY & DEMAND", inline = 'bear')
bear_css        = input.color(color.new(#ffffff, 1), '', group = "SUPPLY & DEMAND", inline = 'bear')
bear_avg_css    = input.color(color.new(#ffffff, 1), '', group = "SUPPLY & DEMAND", inline = 'bear')
bull_ext_last   = input.int(1, 'DEMAND', minval = 1, group = "SUPPLY & DEMAND", inline = 'bull')
bg_bull_css     = input.color(color.new(#00ff0a, 90), '', group = "SUPPLY & DEMAND", inline = 'bull')
bull_css        = input.color(color.new(#ffffff, 1), '', group = "SUPPLY & DEMAND", inline = 'bull')
bull_avg_css    = input.color(color.new(#ffffff, 1), '', group = "SUPPLY & DEMAND", inline = 'bull')
line_style      = input.string("Solid", "LINE STYLE", ["Solid", "Dotted", "Dashed"], group = "SUPPLY & DEMAND")
line_width      = input.int(2, 'LINE WIDTH', minval = 1, group = "SUPPLY & DEMAND")
// Support & Resistance
enableSR        = input(true, "SUPPORT & RESISTANCE ON/Off", group="SUPPORT & RESISTANCE")
colorSup        = input(#00dbff, "SUPPORT", group="SUPPORT & RESISTANCE")
colorRes        = input(#E91E63, "RESISTANCE", group="SUPPORT & RESISTANCE")
strengthSR      = input.int(6, "S/R STRENGTH", 1, group="SUPPORT & RESISTANCE")
lineStyle       = input.string("Solid", "LINE STYLE", ["Solid", "Dotted", "Dashed"], group="SUPPORT & RESISTANCE")
lineWidth       = input.int(2, "LINE WIDTH", 1, group="SUPPORT & RESISTANCE")
expandSR        = input(true, "EXTEND LINES", group = "SUPPORT & RESISTANCE")
useZones        = input(true, "ZONE ON/OFF", group="SUPPORT & RESISTANCE")
useHLZones      = input(true, "HIGH LOW ZONES ON/OFF", group="SUPPORT & RESISTANCE")
zoneWidth       = input.int(4, "ZONE WIDTH %", 0, tooltip="it's calculated using % of the distance between highest/lowest in last 300 bars", group="SUPPORT & RESISTANCE")
// Wave
price           = plot(close, title="Close Line", linewidth=3, color=color.blue, editable=false, display = display.none)

// TREND
// Functions
lineStyle1    =   (styleOption == "Dotted ┈") ? line.style_dotted :
                  (styleOption == "Dashed ╌") ? line.style_dashed :
                  (styleOption == "Arrow Left ←") ? line.style_arrow_left :
                  (styleOption == "Arrow Right →") ? line.style_arrow_right :
                  (styleOption == "Arrows Both ↔") ? line.style_arrow_both :
                  line.style_solid

supertrend(_src, factor, atrLen) =>
	atr = ta.atr(atrLen)
	upperBand = _src + factor * atr
	lowerBand = _src - factor * atr
	prevLowerBand = nz(lowerBand[1])
	prevUpperBand = nz(upperBand[1])
	lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
	upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
	int direction = na
	float superTrend = na
	prevSuperTrend = superTrend[1]
	if na(atr[1])
		direction := 1
	else if prevSuperTrend == prevUpperBand
		direction := close > upperBand ? -1 : 1
	else
		direction := close < lowerBand ? 1 : -1
	superTrend := direction == -1 ? lowerBand : upperBand
	[superTrend, direction]
lr_slope(_src, _len) =>
    x = 0.0, y = 0.0, x2 = 0.0, xy = 0.0
    for i = 0 to _len - 1
        val = _src[i]
        per = i + 1
        x += per
        y += val
        x2 += per * per
        xy += val * per
    _slp = (_len * xy - x * y) / (_len * x2 - x * x)
    _avg = y / _len
    _int = _avg - _slp * x / _len + _slp
    [_slp, _avg, _int]
lr_dev(_src, _len, _slp, _avg, _int) =>
    upDev = 0.0, dnDev = 0.0
    val = _int
    for j = 0 to _len - 1
        price = high[j] - val
        if price > upDev
            upDev := price
        price := val - low[j]
        if price > dnDev
            dnDev := price
        price := _src[j]
        val += _slp
    [upDev, dnDev]

barsL       = 10
barsR       = 10
pivotHigh = fixnan(ta.pivothigh(barsL, barsR)[1])
pivotLow = fixnan(ta.pivotlow(barsL, barsR)[1])
source = close, period = 150
[s, a, i] = lr_slope(source, period)
[upDev, dnDev] = lr_dev(source, period, s, a, i)

y1 = low - (ta.atr(30) * 2), y1B = low - ta.atr(30)
y2 = high + (ta.atr(30) * 2), y2B = high + ta.atr(30)
x1 = bar_index - period + 1, _y1 = i + s * (period - 1), x2 = bar_index, _y2 = i

upperTL = autoTL ? line.new(x1, _y1 + upDev, x2, _y2 + upDev, xloc.bar_index, expandTrend ? extend.both : extend.none, width=lineWidth1, style = lineStyle1, color=upperTL1) : na
line.delete(upperTL[1])
middleTL = autoTL ? line.new(x1, _y1, x2, _y2, xloc.bar_index, expandTrend ? extend.both : extend.none, width=lineWidth1, style = lineStyle1, color=middleTL2) : na
line.delete(middleTL[1])
lowerTL = autoTL ? line.new(x1, _y1 - dnDev, x2, _y2 - dnDev, xloc.bar_index, expandTrend ? extend.both : extend.none, width=lineWidth1, style = lineStyle1, color=lowerTL3) : na
line.delete(lowerTL[1])

// SUPPLY & DEMAND
//Functions 
get_line_style(style) =>
    out = switch style
        "Solid"  => line.style_solid
        "Dotted" => line.style_dashed
        "Dashed" => line.style_dotted

//Function to get order block coordinates
get_coordinates(condition, top, btm, ob_val)=>
    var ob_top  = array.new_float(0)
    var ob_btm  = array.new_float(0)
    var ob_avg  = array.new_float(0)
    var ob_left = array.new_int(0)

    float ob = na

    //Append coordinates to arrays
    if condition and enableSD
        avg = math.avg(top, btm)
        
        array.unshift(ob_top, top)
        array.unshift(ob_btm, btm)
        array.unshift(ob_avg, avg)
        array.unshift(ob_left, time[length])
        
        ob := ob_val
    
    [ob_top, ob_btm, ob_avg, ob_left, ob]

//Function to remove mitigated order blocks from coordinate arrays
remove_mitigated(ob_top, ob_btm, ob_left, ob_avg, target, bull)=> 
    mitigated = false
    target_array = bull ? ob_btm : ob_top

    for element in target_array
        idx = array.indexof(target_array, element)

        if (bull ? target < element : target > element)
            mitigated := true

            array.remove(ob_top, idx) 
            array.remove(ob_btm, idx) 
            array.remove(ob_avg, idx) 
            array.remove(ob_left, idx) 
    
    mitigated

//Function to set order blocks
set_order_blocks(ob_top, ob_btm, ob_left, ob_avg, ext_last, bg_css, border_css, lvl_css)=>
    var ob_box = array.new_box(0)
    var ob_lvl = array.new_line(0)

    //Fill arrays with boxes/lines
    if barstate.isfirst
        for i = 0 to ext_last-1
            array.unshift(ob_box, box.new(na,na,na,na, xloc = xloc.bar_time, extend = extend.right, bgcolor = bg_css, border_color = color.new(border_css, 70)))
            array.unshift(ob_lvl, line.new(na,na,na,na, xloc = xloc.bar_time, extend = extend.right, color = lvl_css, style = get_line_style(line_style), width = line_width))

    //Set order blocks
    if barstate.islast
        if array.size(ob_top) > 0
            for i = 0 to math.min(ext_last-1, array.size(ob_top)-1)
                get_box = array.get(ob_box, i)
                get_lvl = array.get(ob_lvl, i)

                box.set_lefttop(get_box, array.get(ob_left, i), array.get(ob_top, i))
                box.set_rightbottom(get_box, array.get(ob_left, i), array.get(ob_btm, i))

                line.set_xy1(get_lvl, array.get(ob_left, i), array.get(ob_avg, i))
                line.set_xy2(get_lvl, array.get(ob_left, i)+1, array.get(ob_avg, i))

//Global elements 
var os = 0
var target_bull = 0.
var target_bear = 0.

n = bar_index
upper = ta.highest(length)
lower = ta.lowest(length)

if mitigation == 'Close'
    target_bull := ta.lowest(close, length)
    target_bear := ta.highest(close, length)
else
    target_bull := lower
    target_bear := upper

os := high[length] > upper ? 0 : low[length] < lower ? 1 : os[1]

phv = ta.pivothigh(volume, length, length)

//Get bullish/bearish order blocks coordinates 
[bull_top
  , bull_btm
  , bull_avg
  , bull_left
  , bull_ob] = get_coordinates(phv and os == 1, hl2[length], low[length], low[length])

[bear_top
  , bear_btm
  , bear_avg
  , bear_left
  , bear_ob] = get_coordinates(phv and os == 0, high[length], hl2[length], high[length])

//Remove mitigated order blocks
mitigated_bull = remove_mitigated(bull_top
  , bull_btm
  , bull_left
  , bull_avg
  , target_bull
  , true)

mitigated_bear = remove_mitigated(bear_top
  , bear_btm
  , bear_left
  , bear_avg
  , target_bear
  , false)

//Set bullish order blocks
set_order_blocks(bull_top
  , bull_btm
  , bull_left
  , bull_avg
  , bull_ext_last
  , bg_bull_css
  , bull_css
  , bull_avg_css)

//Set bearish order blocks
set_order_blocks(bear_top
  , bear_btm
  , bear_left
  , bear_avg
  , bear_ext_last
  , bg_bear_css
  , bear_css
  , bear_avg_css)

// SUPPORT & RESISTANCE
// Functions
percWidth(len, perc) => (ta.highest(len) - ta.lowest(len)) * perc / 100

// Get components
rb            = 10
prd           = 284
ChannelW      = 10
label_loc     = 55
style         = (lineStyle == "Dotted") ? line.style_dotted :
                     (lineStyle == "Dashed") ? line.style_dashed :
                     line.style_solid
ph            = ta.pivothigh(rb, rb)
pl            = ta.pivotlow (rb, rb)
sr_levels     = array.new_float(21, na)
prdhighest    = ta.highest(prd)
prdlowest     = ta.lowest(prd)
cwidth        = percWidth(prd, ChannelW)
zonePerc      = percWidth(300, zoneWidth)
aas           = array.new_bool(41, true)
u1            = 0.0, u1 := nz(u1[1])
d1            = 0.0, d1 := nz(d1[1])
highestph     = 0.0, highestph := highestph[1]
lowestpl      = 0.0, lowestpl := lowestpl[1]
var sr_levs   = array.new_float(21, na)
label hlabel  = na, label.delete(hlabel[1])
label llabel  = na, label.delete(llabel[1])
var sr_lines  = array.new_line(21, na)
var sr_linesH = array.new_line(21, na)
var sr_linesL = array.new_line(21, na)
var sr_linesF = array.new_linefill(21, na)
var sr_labels = array.new_label(21, na)
if ph or pl
    for x = 0 to array.size(sr_levels) - 1
        array.set(sr_levels, x, na)
    highestph := prdlowest
    lowestpl := prdhighest
    countpp = 0
    for x = 0 to prd
        if na(close[x])
            break
        if not na(ph[x]) or not na(pl[x])
            highestph := math.max(highestph, nz(ph[x], prdlowest), nz(pl[x], prdlowest))
            lowestpl := math.min(lowestpl, nz(ph[x], prdhighest), nz(pl[x], prdhighest))
            countpp += 1
            if countpp > 40
                break
            if array.get(aas, countpp)
                upl = (ph[x] ? high[x + rb] : low[x + rb]) + cwidth
                dnl = (ph[x] ? high[x + rb] : low[x + rb]) - cwidth
                u1 := countpp == 1 ? upl : u1
                d1 := countpp == 1 ? dnl : d1
                tmp = array.new_bool(41, true)
                cnt = 0
                tpoint = 0
                for xx = 0 to prd
                    if na(close[xx])
                        break
                    if not na(ph[xx]) or not na(pl[xx])
                        chg = false
                        cnt += 1
                        if cnt > 40
                            break
                        if array.get(aas, cnt)
                            if not na(ph[xx])
                                if high[xx + rb] <= upl and high[xx + rb] >= dnl
                                    tpoint += 1
                                    chg := true
                            if not na(pl[xx])
                                if low[xx + rb] <= upl and low[xx + rb] >= dnl
                                    tpoint += 1
                                    chg := true
                        if chg and cnt < 41
                            array.set(tmp, cnt, false)
                if tpoint >= strengthSR
                    for g = 0 to 40 by 1
                        if not array.get(tmp, g)
                            array.set(aas, g, false)
                    if ph[x] and countpp < 21
                        array.set(sr_levels, countpp, high[x + rb])
                    if pl[x] and countpp < 21
                        array.set(sr_levels, countpp, low[x + rb])

// Plot
var line highest_ = na, line.delete(highest_)
var line lowest_  = na, line.delete(lowest_)
var line highest_fill1 = na, line.delete(highest_fill1)
var line highest_fill2 = na, line.delete(highest_fill2)
var line lowest_fill1  = na, line.delete(lowest_fill1)
var line lowest_fill2  = na, line.delete(lowest_fill2)
hi_col = close >= highestph ? colorSup : colorRes
lo_col = close >= lowestpl  ? colorSup : colorRes
if enableSR
    highest_ := line.new(bar_index - 311, highestph, bar_index, highestph, xloc.bar_index, expandSR ? extend.both : extend.none, hi_col, style, lineWidth)
    lowest_  := line.new(bar_index - 311, lowestpl , bar_index, lowestpl , xloc.bar_index, expandSR ? extend.both : extend.none, lo_col, style, lineWidth)
    if useHLZones
        highest_fill1 := line.new(bar_index - 311, highestph + zonePerc, bar_index, highestph + zonePerc, xloc.bar_index, expandSR ? extend.both : extend.none, na)
        highest_fill2 := line.new(bar_index - 311, highestph - zonePerc, bar_index, highestph - zonePerc, xloc.bar_index, expandSR ? extend.both : extend.none, na)
        lowest_fill1  := line.new(bar_index - 311, lowestpl + zonePerc , bar_index, lowestpl + zonePerc , xloc.bar_index, expandSR ? extend.both : extend.none, na)
        lowest_fill2  := line.new(bar_index - 311, lowestpl - zonePerc , bar_index, lowestpl - zonePerc , xloc.bar_index, expandSR ? extend.both : extend.none, na)
        linefill.new(highest_fill1, highest_fill2, color.new(hi_col, 80))
        linefill.new(lowest_fill1 , lowest_fill2 , color.new(lo_col, 80))
if ph or pl
    for x = 0 to array.size(sr_lines) - 1
        array.set(sr_levs, x, array.get(sr_levels, x))
for x = 0 to array.size(sr_lines) - 1
    line.delete(array.get(sr_lines, x))
    line.delete(array.get(sr_linesH, x))
    line.delete(array.get(sr_linesL, x))
    linefill.delete(array.get(sr_linesF, x))
    if array.get(sr_levs, x) and enableSR
        line_col = close >= array.get(sr_levs, x) ? colorSup : colorRes
        array.set(sr_lines, x, line.new(bar_index - 355, array.get(sr_levs, x), bar_index, array.get(sr_levs, x), xloc.bar_index, expandSR ? extend.both : extend.none, line_col, style, lineWidth))
        if useZones
            array.set(sr_linesH, x, line.new(bar_index - 355, array.get(sr_levs, x) + zonePerc, bar_index, array.get(sr_levs, x) + zonePerc, xloc.bar_index, expandSR ? extend.both : extend.none, na))
            array.set(sr_linesL, x, line.new(bar_index - 355, array.get(sr_levs, x) - zonePerc, bar_index, array.get(sr_levs, x) - zonePerc, xloc.bar_index, expandSR ? extend.both : extend.none, na))
            array.set(sr_linesF, x, linefill.new(array.get(sr_linesH, x), array.get(sr_linesL, x), color.new(line_col, 80)))

// Wave
len1 = 9
src1 = close
out1 = ta.ema(src1, len1)
ema1color = out1 > out1[1] ? #00bcd4 : #e91e63
ema1 = plot(out1, title='EMA 9', color=color.new(ema1color, 50), offset=0, editable = false, display = display.none)
fill(price, ema1,  title='EMA 9 Fill', color=color.new(ema1color, 90), editable=true)
len3 = 55
src3 = close
out3 = ta.ema(src3, len3)
ema3color = out3 > out3[1] ? #00bcd4 : #e91e63
ema3 = plot(out3, title='EMA 55', linewidth=3, color=color.new(ema3color, 50), offset=0, editable=false, display = display.none)
fill(price, ema3, title='EMA 55 Fill', color=color.new(ema3color, 90), editable=true)
len4 = 100
src4 = close
out4 = ta.ema(src4, len4)
ema4color = out4 > out4[1] ? #00bcd4 : #e91e63
ema4 = plot(out4, title='EMA 100', linewidth=3, color=color.new(ema4color, 50), offset=0, editable=false, display = display.none)
fill(price, ema4, title='EMA 100 Fill', color=color.new(ema4color, 90), editable=true)
len5 = 200
src5 = close
out5 = ta.ema(src5, len5)
ema5color = out5 > out5[1] ? #00bcd4 : #e91e63
ema5 = plot(out5,'EMA 200', linewidth=3, color=color.new(ema5color, 50), offset=0, editable=false, display = display.none)
fill(price, ema5, title='EMA 200 Fill', color=color.new(ema5color, 90), editable=true)



